package com.hfi.security.browser;

import com.hfi.security.core.authentication.AbstractChannelSecurityConfig;
import com.hfi.security.core.authentication.ValidateCodeAuthenticationSecurityConfig;
import com.hfi.security.core.authentication.authorize.AuthorizeConfigManager;
import com.hfi.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.hfi.security.core.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.social.security.SpringSocialConfigurer;

import javax.sql.DataSource;

/**
 * @author ChangLiang
 * @date 2019/8/5
 */
@Configuration
public class BrowserSecurityConfig extends AbstractChannelSecurityConfig {

    @Autowired
    private AuthorizeConfigManager authorizeConfigManager;

    @Autowired
    private SpringSocialConfigurer hfiSocialSecurityConfig;

    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    @Autowired
    private ValidateCodeAuthenticationSecurityConfig validateCodeAuthenticationSecurityConfig;

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private AuthenticationSuccessHandler hfiAuthenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler hfiAuthenticationFailureHandler;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService hfiUserDetailService;

    @Autowired
    private InvalidSessionStrategy hfiInvalidSessionStrategy;

    @Autowired
    private LogoutSuccessHandler hfiLogoutSuccessHandler;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 加入验证密码配置
        applyPasswordAuthenticationConfig(http);

        http.
                // 验证码Filter(包括图形验证码 和 短信验证码)
                apply(validateCodeAuthenticationSecurityConfig)
                .and()
                // 拦截短信登录请求 处理/authentication/mobile请求
                .apply(smsCodeAuthenticationSecurityConfig)
                .and()
                // 加入SocialAuthenticationFilter
                .apply(hfiSocialSecurityConfig)
                .and()
                // 记住我 功能(浏览器特有)
                .rememberMe()
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
                .userDetailsService(hfiUserDetailService)
                .and()
                // 加入session manage相关的内容
                .sessionManagement()
                    .invalidSessionStrategy(hfiInvalidSessionStrategy)
                    .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
                    // 设置为true 当前用户已经有一个session存在了，那么就不允许其他的并发登录了
                    .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
                    .and()
                // 加入退出登录
                .and()
                .logout()
                    // 支持自定义 默认是logout
                    .logoutUrl("/logout")
                    // 配置了logoutSuccessHandler 那么logoutSuccessUrl就不生效了
                    .logoutSuccessUrl("/hfi-logout.html")
                    .logoutSuccessHandler(hfiLogoutSuccessHandler)
                    // 退出时删除浏览器中的cookie
                    .deleteCookies("JSESSIONID")
                .and()
               // 浏览器特有的一些公共url
                .csrf().disable()
        ;

        authorizeConfigManager.config(http.authorizeRequests());
    }
}
